interface FileIO {
  file: File;
  text: (encoding?: string) => Promise<string>;
  toDataUrl: () => Promise<string>;
  toBinaryString: () => Promise<string>;
  toArrayBuffer: () => Promise<ArrayBuffer>;
}

/**
 * 本地文件读取
 * @param accept 读取的文件类型
 * @param size 文件大小
 * @returns
 */
export async function readLocalFile(accept?: string, size?: number): Promise<FileIO> {
  return new Promise((resolve, reject) => {
    const input = document.createElement('input');
    input.type = 'file';
    // 接受的类型
    accept && (input.accept = accept);
    input.onchange = function () {
      const file = input.files![0];
      // 文件类型
      if (accept && file.type ? !new RegExp(accept).test(file.type) : !file.name.endsWith(accept!)) {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject({
          type: 'type',
          message: `文件类型不匹配，应该为${accept}类型文件`,
        });
      }
      // 字节超出
      if (size && file.size / 1000 > size) {
        // eslint-disable-next-line prefer-promise-reject-errors
        reject({
          type: 'size',
          message: `超出最大字节：${size}KB`,
        });
      }

      // 构造文件读取方法
      function readFile<T>(name: string): (...rest: any[]) => Promise<T> {
        return function (...rest: any[]) {
          const reader = new FileReader();

          return new Promise((resolve2, reject2) => {
            reader.onerror = function (err) {
              reject2({ type: 'read', message: err });
            };
            reader.onload = function () {
              resolve2(reader.result as any);
            };
            reader[name](file, ...rest);
          });
        };
      }
      const res = {
        file,
        text: readFile<string>('readAsText'),
        toDataUrl: readFile<string>('readAsDataURL'),
        toBinaryString: readFile<string>('readAsBinaryString'),
        toArrayBuffer: readFile<ArrayBuffer>('readAsArrayBuffer'),
      };

      resolve(res);
    };

    input.click();
  });
}

/**
 * 保存为本地文件
 * @param value 内容
 * @param fileName 文件名
 */
export function saveAsLocalFile(value: string | MediaSource | Blob, fileName: string) {
  // 字符串转文件
  if (typeof value === 'string') {
    value = new File([value], fileName, { type: 'text/plain' });
  }

  saveFromUrl(URL.createObjectURL(value), { fileName });
}

/**
 * 从 url 保存文件
 * @param url 文件地址
 * @param fileName 文件名称
 */
export function saveFromUrl(url: string, config?: { fileName?: string; isBlank?: boolean }) {
  const { fileName, isBlank } = config || {};

  const a = document.createElement('a');

  if (isBlank) {
    a.target = '_blank';
  }

  if (fileName) {
    a.download = fileName;
  } else {
    a.setAttribute('download', '');
  }

  a.href = url;
  a.click();
}
